/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package org.openbookformat.defaultparser;

import com.smallutil.common.CharUtil;
import com.smallutil.io.FileRW;
import java.awt.Toolkit;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.StringSelection;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import javax.swing.JOptionPane;
import org.openbookformat.tags.CompositeTag;
import org.openbookformat.tags.FnMarkTag;
import org.openbookformat.tags.FnTextTag;
import org.openbookformat.tags.FootnoteTag;
import org.openbookformat.tags.FormatTag;
import org.openbookformat.tags.HeadingTag;
import org.openbookformat.tags.PoetTag;
import org.openbookformat.tags.SuperScriptTag;
import org.openbookformat.tags.Tag;
import org.openbookformat.tags.TagType;
import org.openbookformat.tags.Text;

/**
 *
 * @author MUFEED
 */
public class LatexConvertor {
    private LatexOptions texOpt;
    private String NL = "\n";

    public LatexConvertor(LatexOptions texOpt) {
        this.texOpt = texOpt;
    }

    public String convert(CompositeTag tags) {
        StringBuffer buff = new StringBuffer();

        //Setup preamble
        preamble(buff, tags);

        //begin document
        buff.append(NL);
        buff.append("\\begin{document}" + NL);
        buff.append("\\selectlanguage{arabic}" + NL);

        titlepage(buff);
        buff.append("\\tableofcontents" + NL);
        buff.append("\\vfill" + NL);
        buff.append("\\pagebreak" +NL);
        buff.append("% disables chapter, section and subsection numbering").append(NL);
        buff.append("\\setcounter{secnumdepth}{-1}").append(NL);
        buff.append("\\renewcommand{\\baselinestretch}{1.2}").append(NL);
        buff.append("\\omega").append(NL) ;
        
        //begin document
        
        //convert tags
        buff.append(convertCompTag(tags));

        buff.append("\\end{document}" + NL);
        return buff.toString();
    }

    private String convertCompTag(CompositeTag tags, CompositeTag ftags) {
        String val = "";
        for (int i = 0; i < tags.size(); i++)
            val += convertTag(tags, i, ftags);
        return val;
    }

    private String convertCompTag(CompositeTag tags) {
        return convertCompTag(tags, tags);
    }

    private void preamble(StringBuffer buff, CompositeTag tags) {
        buff.append("\\documentclass{book}" + NL);
        buff.append("\\usepackage{cmap}" + NL);
        buff.append("\\usepackage[utf8]{inputenc}" + NL);
        buff.append("\\usepackage[LAE,LFE]{fontenc}" + NL);
        buff.append("\\usepackage[arabic, farsi, english]{babel}" + NL);
        buff.append("\\TOCLanguage{arabic}" + NL);
        buff.append("\\usepackage[usenames]{color}" + NL);
        buff.append("\\usepackage{footnpag}" + NL);
        buff.append("\\usepackage{poetry}" +NL);
        buff.append("\\setversedim{55mm}{-20mm}" + NL);

        buff.append(NL);

        //pdf page
        buff.append(reformat("pdfpageheight", texOpt.getOptions(
                "page", "pdfpageheight"), PAGE_OPTION_FORMAT));
        buff.append(reformat("pdfpagewidth", texOpt.getOptions(
                "page", "pdfpagewidth"), PAGE_OPTION_FORMAT));

        //pager dim
        buff.append(reformat("paperheight", texOpt.getOptions(
                "page", "paperheight"), PAGE_OPTION_FORMAT));
        buff.append(reformat("paperwidth", texOpt.getOptions(
                "page", "paperwidth"), PAGE_OPTION_FORMAT));
        buff.append(NL);

        //text dim
        buff.append(reformat("textheight", texOpt.getOptions(
                "page", "textheight"), PAGE_OPTION_FORMAT));
        buff.append(reformat("textwidth", texOpt.getOptions(
                "page", "textwidth"), PAGE_OPTION_FORMAT));
        buff.append(NL);

        //offset
        buff.append(reformat("voffset", texOpt.getOptions(
                "page", "voffset"), PAGE_OPTION_FORMAT));
        buff.append(reformat("hoffset", texOpt.getOptions(
                "page", "hoffset"), PAGE_OPTION_FORMAT));
        buff.append(NL);

        //margin
        buff.append(reformat("oddsidemargin", texOpt.getOptions(
                "page", "oddsidemargin"), PAGE_OPTION_FORMAT));
        buff.append(reformat("evensidemargin", texOpt.getOptions(
                "page", "evensidemargin"), PAGE_OPTION_FORMAT));
        buff.append(reformat("topmargin", texOpt.getOptions(
                "page", "topmargin"), PAGE_OPTION_FORMAT));
        buff.append(reformat("headheight", texOpt.getOptions(
                "page", "headheight"), PAGE_OPTION_FORMAT));
        buff.append(reformat("headsep", texOpt.getOptions(
                "page", "headsep"), PAGE_OPTION_FORMAT));
        buff.append(reformat("footskip", texOpt.getOptions(
                "page", "footskip"), PAGE_OPTION_FORMAT));
        buff.append(NL);

        buff.append("\\newcommand{\\superscript}[1]{\\ensuremath{^{\\textrm{#1}}}}" +NL);
        buff.append("\\newcommand{\\subscript}[1]{\\ensuremath{_{\\textrm{#1}}}}" + NL);
//        buff.append("\\small" + NL);

        
    }

    private void titlepage(StringBuffer buff) {
        String title = "مجموعة المحاضرات\\ التي ألقاها\\\\" + 
"الخطيب البارع العلامة الشيخ\\\\" +
"محمد تقي فلسفي في جامع\\\\" + 
"سيد عزيز الله ـ طهران\\\\" + 
"في رمضان 1381 هـ";

        
        String author = "الشيخ محمد جواد آل الفقيه";
        String series = "سلسلة الأركان الأربعة\\\\ 2";

        buff.append("\\begin{titlepage}" + NL);
//	buff.append("\t\\begin{flushleft}" + NL);
//	buff.append("\t\t\\parbox[c]{0.4\\textwidth}{" + NL);
//        buff.append("\t\t\t\\small" + NL);
//        buff.append("\t\t\t\\begin{center}" + NL);
//	buff.append("\t\t\t\t" + series + NL);
//	buff.append("\t\t\t\\end{center}" + NL);
//	buff.append("\t\t}" + NL);
//	buff.append("\t\\end{flushleft}" + NL);

	buff.append("\t\\ \\\\ \\\\ \\\\" + NL);

	buff.append("\t\\begin{center}" + NL);
        buff.append("\t\t\\texthor{ \\large" + NL);
	buff.append("\t\t\t" + title + NL);
        buff.append("\t\t}" + NL);
	buff.append("\t\\end{center}" + NL);

//	buff.append("\t\\begin{center}" + NL);
//	buff.append("\t\t\\parbox[c]{0.7\\textwidth}{" + NL);
//	buff.append("\t\t\t\\begin{center}" + NL);
//        buff.append("\t\t\t\t\\textthol{" + NL);
//        buff.append("\t\t\t\t\t\\emph{تأليف} \\ \\\\" + NL);
//        buff.append("\t\t\t\t\t" + author + NL);
//        buff.append("\t\t\t\t}" + NL);
//	buff.append("\t\t\t\\end{center}" + NL);
//	buff.append("\t\t}" + NL);
//	buff.append("\t\\end{center} " + NL);

        buff.append("\t\\vfil" + NL);
        buff.append("\\end{titlepage}" + NL);

    }
    private String convertTag(CompositeTag tags, int tagIdx) {
        return convertTag(tags, tagIdx, tags);
    }

    private String convertTag(CompositeTag tags, int tagIdx, CompositeTag fTags) {
        Tag tag = tags.getTag(tagIdx);
        String rVal = tag.getClass().getSimpleName() + NL;
        rVal = "";
        TagType type = TagType.BF.getTagType(tag);
        
        switch (type) {
            case BF:
                //rVal = "\\textbf{" + ()
                break;
            case HEADING:
                int level = ((HeadingTag) tag).getLevel();
                boolean intoc = ((HeadingTag) tag).isInTOC();
                boolean tocText = ((HeadingTag) tag).getToc_text() != null;
                if(tocText)
                    System.out.println("convertCompTag(((HeadingTag) tag).getToc_text(), fTags)" + convertCompTag(((HeadingTag) tag).getToc_text(), fTags));
                if (intoc) {
                    if(level  > 4) {
                        rVal = "\bf{" + convertCompTag(((HeadingTag) tag).
                                getText(), fTags).trim() + "}" + NL;
                    } else {
                        rVal = "\\" + (level == 4?"subsubsection":"")
                                + (level == 3?"subsection":"")
                                + (level == 2?"section":"")
                                + (level == 1?"chapter":"")
                                //+ (intoc?"":"*") 
                                + (tocText ? "[" + convertCompTag(((HeadingTag) tag).getToc_text(), fTags).trim() + "]":"")
                                + "{" + convertCompTag(((HeadingTag) tag).getText(), fTags).trim() + "}";
                    }
                    rVal = fixArabi(rVal.replace("\n", "")).replace("\\par", "\\\\") + NL;
                } else {
                    rVal = convertCompTag(((HeadingTag) tag).getText(), fTags).trim();
                    rVal = "\\begin{center}" + NL
                            + "\t\\large" + NL
                            + rVal + NL
                            + "\\end{center}"+ NL;
                    rVal = fixArabi(rVal).replace("\\par", "\\\\");
                }
                break;
            case FN_MARK:
                String mark = ((FnMarkTag) tag).getMark();
                //find the next fn text
                
                int fnTextIdx = fTags.indexOf(TagType.FOOTNOTE, tagIdx);
                FootnoteTag footnote = (FootnoteTag) fTags.getTag(fnTextIdx);
                System.out.println("tagIdx:" + tagIdx + "\t" + fnTextIdx);
                for (int i = 0; i < footnote.size(); i++) {
                    System.out.println(mark + "=" + footnote.getFnTextTag(i).getMark());
                    if(mark.equals( footnote.getFnTextTag(i).getMark())) {
                        rVal = footnote.getFnTextTag(i).getText().toString();
                        System.out.println("\t\t\trVal: " + rVal );
                        break;
                    }
                }

                rVal = "\\footnote{" + fixArabi(rVal) + "}";
                break;
            case FORMAT:
                System.out.println("\t\t\t" + convertCompTag(((FormatTag) tag).getText(),
                        fTags));
                rVal = "\\textmash[" + fixArabi(convertCompTag(((FormatTag) tag).getText(),
                        fTags)) + "]";
                rVal = rVal.replace("\\par", " ");
                break;
            case PAGEBREAK:
                //rVal = "- \\I{" + ((PagebreakTag) tag).getPageNumber() + "} -";
                //rVal = "\\begin{center}" + NL + "\t" + rVal + NL + "\\end{center}\n";
                break;
            case PAR:
                rVal = "\\par" + NL;
                break;
            case POET:
                rVal  = "\\par" + NL + "\\textnada{" + NL;

                int i = 0;
                rVal += "\t\\Halfverses{  }{" + fixArabi(convertCompTag(((PoetTag) tag).getRhyme(i).
                    getVerse(0)).trim().replace("\n", "")) + "}" + NL;
                for (; i < ((PoetTag) tag).size() -1; i++)
                    rVal += "\t\\Halfverses{" + fixArabi(convertCompTag(((PoetTag) tag).getRhyme(i).getVerse(1), tags).trim().replace("\n", "")) + "}{"
                            + fixArabi(convertCompTag(((PoetTag) tag).getRhyme(i+1).getVerse(0), tags).trim().replace("\n", "")) + "}" + NL;
                rVal += "\t\\Halfverses{" + fixArabi(convertCompTag(((PoetTag) tag).getRhyme(i).getVerse(1), tags).trim().replace("\n", "")) + "}{ }" + NL;

//                for (; i < ((PoetTag) tag).size(); i++) {
//                    rVal += "\t\\Halfverses{  }{" + fixVowels(convertCompTag(((PoetTag) tag).getRhyme(i).
//                    getVerse(0)).trim().replace("\n", "")) + "}" + NL;
//                    rVal += "\t\\Halfverses{" + fixVowels(convertCompTag(((PoetTag) tag).getRhyme(i).getVerse(1), tags).trim().replace("\n", "")) + "}{ }" + NL;
//                    rVal += "\t\\nopagebreak[2]" + NL;
//                }

                rVal += "}" + NL;
                break;
            case TEXT:
                rVal = "\t" + fixArabi(((Text) tag).getText()) + "\n";
                break;
            case SUPER_SCRIPT:
                rVal = "\\superscript{\\textAR{" + convertCompTag(((SuperScriptTag)
                        tag).getText(), tags).trim().replace("\n", "") + "}}" ;
//            case
        }

        return rVal;
    }

    private String fixArabi(String text) {
        String rVal = text;
        if(hasEscapleLetters(text))
            rVal = escapleLatex(text);
        if(hasFarsiLetters(rVal))
            rVal = "\\begin{otherlanguage}{farsi}" + rVal + "\\end{otherlanguage}";
        rVal =  fixVowels(fixArabicDigits(rVal));
        return rVal;
    }

    private String fixVowels(String text)  {
        String rVal ="";
        String words[] = text.trim().split(" ");
        String tmp = null;
        for (int i = 0; i < words.length; i++) {
            tmp = words[i].trim();
            if (tmp.length() > 1
                    && isVowel(tmp.charAt(tmp.length()-1) + "")
                    && isConnectingChar(tmp.charAt(tmp.length()-2) + "")) {
                tmp = tmp.substring(0, tmp.length() - 1) + "*" + tmp.charAt(tmp.length()-1);
            }

            if (tmp.length() > 2
                    && isVowel(tmp.charAt(tmp.length()-1) + "")
                    && isVowel(tmp.charAt(tmp.length()-2) + "")
                    && isConnectingChar(tmp.charAt(tmp.length()-3) + "")) {
                tmp = tmp.substring(0, tmp.length() - 2) + "*"
                        + tmp.substring(tmp.length() - 2, tmp.length());
            }
            if(tmp.length() > 0)
                rVal += tmp + " ";
        }

        return rVal;
    }

    private String fixArabicDigits(String text) {
        String rVal = text;
        int count = 0;
        for (int i = 0; i < rVal.length(); i++) {
            if (CharUtil.isNumber(rVal.charAt(i))) {
                count++;
            }  else {
                if(count > 1) {
                    rVal = rVal.substring(0, i - count) + "\\I{"
                            + rVal.substring(i - count, i) + "}"
                            + rVal.substring(i);
                    i = i + 4;
                }
                count = 0;
            }
        }
        return rVal;
    }
    
    public static String[] escTex = {"#", "$", "%", "&", "~", "_", "^", "{", 
                "}", "<", ">", "\\"}; 
    
    public String escapleLatex(String text) {
        String rVal = text;
        rVal = rVal.replaceAll("([_^])", "\\1");
//        rVal = rVal.replaceAll("([#$%&~_^{}])", "\\1");
//        rVal = rVal.replaceAll("([\\<\\>])", "\\$\\1\\$");
//        //rVal = rVal.replace("\\\\", "$\\backslash$");
        return rVal;
    }
   
    private boolean hasEscapleLetters(String c) {
        for(int i = 0; i < escTex.length; i++)
            if(c.contains(escTex[i]))
                return true;
        return false;
    }
    
    public static String[] farsiLetters = {
        "گ",
        "پ"
    };
    
    private boolean hasFarsiLetters(String c) {
        for(int i = 0; i < farsiLetters.length; i++)
            if(c.contains(farsiLetters[i]))
                return true;
        return false;
    }

    private boolean isConnectingChar(String c) {
        return "ب ت ث ج ح خ س ش ص ض ط ظ ع غ ف ق ك ل م ن ه ي".contains(c);
    }

    private boolean isVowel(String c) {
        return "ٌ ُ ً َ ٍ ِ ّْ".contains(c);
    }

    private final int PAGE_OPTION_FORMAT = 001;

    private String reformat(String key, String val, int format) {
        if (val == null)
            return "";
        switch (format) {
            case PAGE_OPTION_FORMAT:
                return "\\setlength{\\" + key + "}{" + val + "}" + NL;
        }
        return null;
    }

    public static void main(String args[]) throws Exception {
        String options =
                "%page options\n" +
                "page.pdfpagewidth = 90mm\n" +
                "page.pdfpageheight = 120mm\n" +
                "page.paperwidth = 90mm\n" +
                "page.paperheight = 120mm\n" +
                "page.textwidth = 70mm\n" +
                "page.textheight = 112mm\n" +
                "page.hoffset = 0pt\n" +
                "page.voffset = 0pt\n" +
                "page.marginparwidth = 0pt\n" +
                "page.marginparsep = 0pt\n" +
                "page.oddsidemargin = -15mm\n" +
                "page.evensidemargin = -15mm\n" +
                "page.topmargin  = -30mm\n" +
                "page.headheight = 0mm\n" +
                "page.headsep = 10mm\n" +
                "page.footskip = 10mm\n";

        options += "";

        CompositeTag tag = new CompositeTag();
        CompositeTag tmp = new CompositeTag();
        for(int i = 1; i < 6; i++) {
            //String obf_text = FileRW.load("D:\\data\\nbobf\\AlTofil\\src\\Chapter" + i + ".obf", "utf-8");
            //String obf_text = FileRW.load("D:\\Users\\MUFEED\\Documents\\My Dropbox\\OBF\\AlTofil\\src\\Chapter" + i + ".obf", "utf-8");
            //String obf_text = FileRW.load("E:\\M.txt", "utf-8");
            //String obf_text = FileRW.load("D:\\Users\\MUFEED\\Desktop\\سيد المرسلين - الجزاء الأول\\src\\Chapter0"  + i + ".obf", "windows-1256");
            String obf_text = FileRW.load("D:\\data\\compiled\\Ilahiat\\src\\Chapter0"  + i + ".obf", "windows-1256");
            OBFDefaultParser parser = new OBFDefaultParser();
            tmp = (CompositeTag) parser.parse(obf_text);
            for (int j = 0; j < tmp.size(); j++)
                tag.addTag(tmp.getTag(j));                       
        }
        LatexConvertor lc = new LatexConvertor(new LatexOptions(options));
        String out = lc.convert(tag);
        System.out.println("----------------------------------------------");
        System.out.println(out);

        StringSelection stringSelection = new StringSelection( out );
        Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
        clipboard.setContents( stringSelection, null );

    }
}
